package net.takela.common.security.filter;


import net.takela.common.security.SecurityProperties;
import net.takela.common.security.model.AuthUser;
import net.takela.common.security.service.AuthTokenManager;
import net.takela.common.spring.exception.AuthException;
import net.takela.common.spring.exception.StatusCodeException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;


public class TokenAuthFilter extends OncePerRequestFilter {

    private AuthTokenManager authTokenManager;
    private SecurityProperties securityProperties;
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    private Class<? extends AuthUser>  userClass = AuthUser.class;
    /**
     * 
     */
    public TokenAuthFilter(AuthTokenManager authTokenManager, SecurityProperties securityProperties){
        this.authTokenManager = authTokenManager;
        this.securityProperties = securityProperties;
    }

    public Class<? extends AuthUser>  getUserClass() {
        return userClass;
    }
    /**
     * 
     */
    public void setUserClass(Class<? extends AuthUser> userClass) {
        this.userClass = userClass;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        boolean isAnonymous = securityProperties.getAnonymousUrls().stream().anyMatch( url -> antPathMatcher.match(url, request.getRequestURI()) );

        if (!isAnonymous && SecurityContextHolder.getContext().getAuthentication() == null){
            AuthUser user = null;
            try{
                user = authTokenManager.parseUserInfoFromRequest(request, userClass);
            }catch (Exception e){
                AuthException authException = new AuthException();
                request.setAttribute(StatusCodeException.COMMON_EXCEPTION_REQ_KEY, authException);
                throw authException;
            }
            if (user != null){
                List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("0");
                user.setAuthorities(auths);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        user, null, user.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
                        request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }
}
